package nmrworkflow.framework.functionwrappers.nmrpipe;

import java.io.IOException;
import java.util.Vector;

import nmrworkflow.framework.beans.datasets.NmrDataSet;
import nmrworkflow.framework.beans.datasets.NmrPipeDataSet;
import nmrworkflow.framework.beans.datatypes.Streamable;
import nmrworkflow.framework.configuration.Preferences;
import nmrworkflow.framework.executionmodule.ExecutionQueue;
import nmrworkflow.framework.executionmodule.StreamProcessor;
import nmrworkflow.framework.executionmodule.interfaces.DataProcessor;
import nmrworkflow.framework.functionwrappers.Argument;
import nmrworkflow.framework.functionwrappers.Function;
import nmrworkflow.framework.functionwrappers.FunctionWrapper;

/**
 * Base wrapper for all NmrPipe functions.  Handles system interaction so that subclasses
 * can focus on function semantics.
 * 
 * @author rjn
 *
 */
public abstract class BaseNmrPipeWrapper extends FunctionWrapper<NmrPipeDataSet, NmrPipeDataSet> {
	
	public BaseNmrPipeWrapper() {
		super();
	}

	@Override
	public DataProcessor getExecutable() throws IOException, InterruptedException {
		final Vector<String> script = new Vector<String>();
		final String nmrPipePath = Preferences.getInstance().getNmrPipePath().getAbsolutePath();
		ExecutionQueue ec = new ExecutionQueue();
		StreamProcessor executor;
		final Function transpose = getTranspose();
		final Function function = buildFunction();
		String[] transposeCmdLine = null;
		
		script.add("-fn");
		script.add(function.getName());
		
		for(Argument a: function.getArguments()) {
			script.add("-" + a.getKey());
			for(String v: a.getValues())
				script.add(v);
		}
		
		if(transpose != null) {
			transposeCmdLine = new String[] {nmrPipePath, "-fn", transpose.getName()};	

			ec.enqueue(new StreamProcessor<NmrPipeDataSet<Streamable>, NmrPipeDataSet<Streamable>>(NmrPipeDataSet.class, NmrPipeDataSet.class, transposeCmdLine));
		}
		
		String[] cmd = new String[script.size() + 1];
		cmd[0] = nmrPipePath;
		for(int i = 1; i < cmd.length; i++)
			cmd[i] = script.get(i - 1);
		
		executor = new StreamProcessor<NmrPipeDataSet<Streamable>, NmrPipeDataSet<Streamable>>(NmrPipeDataSet.class, NmrPipeDataSet.class, cmd);
		
		ec.enqueue(executor);
		
		if(transpose != null) {
			ec.enqueue(new StreamProcessor<NmrPipeDataSet<Streamable>, NmrPipeDataSet<Streamable>>(NmrDataSet.class, NmrDataSet.class, transposeCmdLine));

			return ec;
		}
		
		return executor;
	}
	
	/**
	 * Builds a Function object for a NMRPipe function using
	 * the data stored in the individiual Wrapper object.
	 * @return
	 */
	protected abstract Function buildFunction();

	/**
	 * Should be overriden in the tool's Executor.
	 * @return
	 */
	protected Function getTranspose() {
		Function transpose;
		
		switch(this.dimension) {
		case 2:
			/*
			 * Transpose X and Y
			 */
			transpose = new Function("TP");
			transpose.addArgument(new Argument("hyper", ""));
			break;
		case 3:
			/*
			 * Transpose X and Z
			 */
			transpose = new Function("ZTP");
			transpose.addArgument(new Argument("hyper", ""));
			break;
		case 4:
			/*
			 * Tranpose A and X
			 */
			transpose = new Function("ATP");
			transpose.addArgument(new Argument("hyper", ""));
			break;
		default:
			transpose = null;
			break;
		}
		
		return transpose;
	}

}
